Skip to content

Configure request headers used in cache keys - #800

Open
maxschmeling wants to merge 21 commits into
trunkfrom
codex/filter-cache-invalidating-headers
Open

Configure request headers used in cache keys#800
maxschmeling wants to merge 21 commits into
trunkfrom
codex/filter-cache-invalidating-headers

Conversation

@maxschmeling

@maxschmeling maxschmeling commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add query-level cache_key_request_headers configuration for HTTP queries
  • always retain Authorization and Cache-Control, merging additional query header names case-insensitively
  • make get_cache_key_request_headers() part of HttpQueryInterface and have QueryRunner consume the query-owned policy directly
  • carry the resolved list in one internal request header used consistently by cache lookup, storage, and logging
  • strip the internal metadata before outbound dispatch and before storing the request in the cache entry
  • configure Shopify’s built-in queries to include the storefront access-token header
  • document the cache-isolation security risk, query-only configuration, and the direct-interface implementation requirement

Security

Remote Data Blocks does not include every request header in cache keys. If a custom header changes authentication, authorization, tenancy, or returned data, every query that uses it must list that header in cache_key_request_headers; otherwise requests with different security contexts can share a cached response.

Headers configured on a data source are not added automatically. The documentation calls this out prominently, including the cross-request and cross-user risk with persistent object caching. The built-in Authorization and Cache-Control defaults cannot be removed.

Compatibility

Direct implementations of HttpQueryInterface must implement get_cache_key_request_headers(). Returning [] uses only the built-in defaults. The extending guide includes an upgrade example.

Testing

  • npm run format:check
  • npm run lint:php
  • npm run lint:js
  • npm run check-types
  • npm test (596 PHP tests / 1,374 assertions; 76 JavaScript tests)
  • npm run build
  • git diff --check

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Test this PR in WordPress Playground.

@maxschmeling maxschmeling changed the title Add filter for cache-invalidating request headers Configure request headers used in cache keys Aug 18, 2026
Comment thread inc/Config/DataSource/HttpDataSource.php Outdated
Comment thread inc/Config/CacheKeyRequestHeadersInterface.php Outdated
Comment thread inc/HttpClient/RdbCacheStrategy.php Outdated
Comment thread inc/HttpClient/RdbCacheMiddleware.php
Comment thread inc/Config/Query/HttpQuery.php Outdated
Comment thread inc/HttpClient/CacheKeyRequestHeaders.php Outdated
Co-authored-by: Chris Zarate <chris.zarate@automattic.com>
Comment thread inc/HttpClient/CacheKeyRequestHeaders.php Outdated
class RdbCacheMiddleware extends \Kevinrob\GuzzleCache\CacheMiddleware {
public const CACHE_KEY_REQUEST_HEADERS_HEADER = 'X-Remote-Data-Blocks-Cache-Key-Headers';

public function __invoke( callable $handler ): callable {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand what is accomplished by this __invoke override. I believe this header is already removed by the RdbCacheStrategy#getCacheObject

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left over duplicate. I've removed it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The __invoke is still present

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I don't think this __invoke has any effect. Can you test this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't. I removed it but didn't get that in the commit I guess. Pushed in 78741db

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This removal actually does cause a test failure.

get_cache_object() removes the header from the request stored in the cache entry, but it runs only after the downstream HTTP handler has returned. This override wraps that handler so the cache strategy can still use the metadata while the transport receives a sanitized request. Without it, the metadata header is sent to the remote API, as covered by testCacheKeyRequestHeaderMetadataIsNotSentToRequestHandler.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also realized this means the TTL value isn't being stripped either. So I've added a test and fix for that as well.

fea0af2

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without it, the metadata header is sent to the remote API

The same is probably true of X-Remote-Data-Blocks-Cache-TTL. Is that bad?

@chriszarate chriszarate Aug 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it is a bad side effect. It's just a request header. But we should pick a policy and be consistent. I'd vote to leave it personally.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I already removed it in the commit I commented above.

I definitely don't think we should be adding headers to requests for internal functions and letting them flow through to the endpoint. Unless you have strong opinions about it, I'm going to go with the approach of stripping them.

Comment thread inc/HttpClient/RdbCacheStrategy.php
Comment thread inc/HttpClient/RdbCacheMiddleware.php Outdated
Comment thread inc/HttpClient/RdbLogMiddleware.php Outdated
Comment thread inc/Config/Query/CacheKeyRequestHeadersAwareInterface.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants